library(readr)
library(dplyr)
library(stringr)
library(purrr)
library(ggplot2)
library(skimr)
ctu19<-read_csv("../datasets/ctu19_result.csv")
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_double(),
  InitialIp = col_character(),
  EndIP = col_character(),
  Port = col_double(),
  Proto = col_character(),
  State = col_character(),
  LabelName = col_character()
)
22184 parsing failures.
 row  col               expected actual                           file
2940 Port no trailing characters  x00d7 '../datasets/ctu19_result.csv'
2941 Port no trailing characters  x00db '../datasets/ctu19_result.csv'
2942 Port no trailing characters  x00ea '../datasets/ctu19_result.csv'
2943 Port no trailing characters  x00ff '../datasets/ctu19_result.csv'
2944 Port no trailing characters  x01d1 '../datasets/ctu19_result.csv'
.... .... ...................... ...... ..............................
See problems(...) for more details.
ctu19 %>% group_by(LabelName) %>% summarise(n=n())

Create dataset

ctu19<- ctu19 %>% select(State,LabelName) 
names(ctu19)<-c("State","class")
ctu19$State <- ctu19$State %>% substr(4,nchar(ctu19$State))
ctu19<-ctu19 %>% filter(State!="")
ctu19 %>% nrow()
[1] 27545
ctu19 %>% group_by(class) %>% summarize(n=n())
ctu19 %>% write_csv("../datasets/ctu19subs2.csv")
names(ctu19)
[1] "State" "class"
ctu19<-readr::read_csv("datasets/ctu19subs.csv")

ctu19<-ctu19 %>% mutate(modelsize=str_count(State,".")) 
ctu19_cleaned<-ctu19 %>% filter (!is.na(Port))

ctu19_cleaned %>% filter(Port < 1024) %>% group_by(modelsize,Port) %>% summarise(n=n()) %>% ungroup() %>% mutate(total=sum(n)) 

ctu19_cleaned %>% filter(modelsize<4) %>% select(State)

ctu19_cleaned$State <- ctu19_cleaned$State %>% substr(4,5000000)
ggplot(ctu19_cleaned %>% filter(Port < 1024))+
  geom_boxplot(aes(x=as.factor(X1),y=modelsize))+
  theme_bw()
  
names(ctu19)
ctu19<-readr::read_csv("datasets/ctu19subs.csv")
ctu19<-ctu19 %>% mutate(modelsize=str_count(State,".")) 
ctu19 %>% filter(modelsize >100) %>% group_by(class) %>% summarise(n=n())

ctu19 %>% nrow()
summary(ctu19)
skim(ctu19 %>% mutate(class=as.factor(class)))

ctu19 %>% select(State) %>% unique() %>% nrow
create_histogram<-function(x){
  valid_characters <- "$abcdefghiABCDEFGHIrstuvwxyzRSTUVWXYZ0123456789" %>% str_split("")
  valid_characters <- valid_characters[[1]] 
  valid_characters[48]="\\."
  valid_characters[49]="\\,"
  valid_characters[50]="\\+"
  valid_characters[51]="\\*"

  freq<- (x %>% map(function(x) str_count(x,valid_characters)) %>% unlist() %>% matrix( ncol = 51, byrow = TRUE) %>% colSums())
  freq<-freq/ sum( str_count(x,".") )
  plot<-data.frame(freq=freq,symbols=valid_characters) %>%
  ggplot()+
  geom_col(aes(x=symbols,y=freq),fill='black',col='black')+
  theme_bw()
  plot
}
n <- (ctu19 %>% filter(class == "Normal" & modelsize <100))$State 

nh<-create_histogram(n)
nh <- nh +  labs(title="CTU19 seq char distribution for Normal [modelsize <100]")

m <- (ctu19 %>% filter(class != "Normal" & modelsize <100))$State 

mh<-create_histogram(m)
mh <- mh +  labs(title="CTU19 seq char distribution for Malware [modelsize <100]")

gridExtra::grid.arrange(nh,mh)
#source("preprocess.R")
#datasets<-build_train_test(datasetfile = "datasets/ctu13subs.csv",maxlen = ctu_maxlen)
# WARNING: to avoid regenerating de train and test sets, just uncomments the following lines
# WARNING: there is no guarantee the files saved correspond to argencon.csv. If unsure, just re-run build_train_test()
load(file='datasets/.train_dataset_keras.rd')
load(file='datasets/.test_dataset_keras.rd')
datasets<-list()
datasets$train<-train_dataset_keras
datasets$test<-test_dataset_keras

### Function Definitions ####
get_predictions <- function(model, test_dataset_x,threshold=0.5) {
  predsprobs<-model %>% predict(test_dataset_x, batch_size=256)
  preds<-ifelse(predsprobs>threshold,1,0)
  return (preds)
}
model<-keras::load_model_hdf5("models/ctu19-lstm_endgame-400-10_model.h5")
summary(model)
preds<-get_predictions(model = model,test_dataset_x =  datasets$test$encode,threshold = 0.5 )
test_results<-data.frame(predicted_class=preds,class=ifelse(grepl("Normal",datasets$test$label) ,0,1) ,domain=datasets$test$domain,label=datasets$test$label) 
#test_results
caret::confusionMatrix(as.factor(test_results$predicted_class),as.factor(test_results$class), positive='1', mode="everything" )
fp<-(test_results %>% mutate(modelsize=str_count(domain,"."))  %>%  filter(class == 0 & predicted_class == 1))
fn<-(test_results %>% mutate(modelsize=str_count(domain,"."))  %>%  filter(class == 1 & predicted_class == 0))
tp<-(test_results %>% mutate(modelsize=str_count(domain,"."))  %>%  filter(class == 1 & predicted_class == 1))
tn<-(test_results %>% mutate(modelsize=str_count(domain,"."))  %>%  filter(class == 0 & predicted_class == 0))


fp_domain<-fp$domain
tp_domain<-tp$domain
fn_domain<-fn$domain
tn_domain<-tn$domain


fp_h<-create_histogram(fp_domain)
fp_h <- fp_h +  labs(title="CTU19 seq char distribution for False Positive")
#fp_h <- fp_h + ylim(0,500)

tp_h<-create_histogram(tp_domain)
tp_h <- tp_h +  labs(title="CTU19 seq char distribution for True Positive")
#tp_h <- tp_h + ylim(0,500)

fn_h<-create_histogram(fn_domain)
fn_h <- fn_h +  labs(title="CTU19 seq char distribution for False Negative")
tn_h<-create_histogram(tn_domain)
tn_h <- tn_h +  labs(title="CTU19 seq char distribution for True Negative")

gridExtra::grid.arrange(fp_h,tp_h,fn_h,tn_h,ncol=1)
#library(scales)
#tp_h + scale_y_continuous(limits=c(0,1000),oob = rescale_none)
#fp_h + scale_y_continuous(limits=c(0,1000),oob = rescale_none)
fp$type<-"fp"
tp$type<-"tp"
tn$type<-"tn"
fn$type<-"fn"

plot<-rbind(fp,tp,tn,fn) %>%
  ggplot()+
  geom_boxplot(aes(x=type,y=modelsize),fill='orange') +
  ylim(0,500)+
  theme_bw()
plot
ggplotly(plot)

pca 2D proyection

source("preprocess.R")
library(abind)
  tp <- tp %>% sample_n(1000)
  fp_tokenized=tokenize(as.matrix(fp$domain),fp$label,maxlen = 100)
  tp_tokenized=tokenize(as.matrix(tp$domain),tp$label,maxlen = 100)
  fn_tokenized=tokenize(as.matrix(fn$domain),fn$label,maxlen = 100)
  tn_tokenized=tokenize(as.matrix(tn$domain),tn$label,maxlen = 100)
  
  
  
  fp_tokenized$res<-rep("FP", length(fp_tokenized$domain))
  tp_tokenized$res<-rep("TP", length(tp_tokenized$domain))
  
  fn_tokenized$res<-rep("FN", length(fn_tokenized$domain))
  tn_tokenized$res<-rep("TN", length(tn_tokenized$domain))
  
  
  malware_results=list()
  malware_results$encode<-abind(fp_tokenized$encode,
                                tp_tokenized$encode,
                                fn_tokenized$encode,
                                tn_tokenized$encode,
                              along=1)
  malware_results$domain<-c(fp_tokenized$domain,
                            tp_tokenized$domain,
                            fn_tokenized$domain,
                            tn_tokenized$domain)
                      
  malware_results$res<-c(fp_tokenized$res,
                         tp_tokenized$res,
                         fn_tokenized$res,
                         tn_tokenized$res
                         )
  malware_results$label<-c(as.character(fp_tokenized$label),
                           as.character(tp_tokenized$label),
                           as.character(fn_tokenized$label),
                           as.character(tn_tokenized$label)
                           
                           )
  
  #nrow(malware_results$encode)
  #length(malware_results$label)
  #length(malware_results$domain)
  
  pca=prcomp(malware_results$encode[,1:20],center=TRUE,scale.=TRUE)
  pca_data<-data.frame(pca$x,res=malware_results$res,label=malware_results$label,domain=malware_results$domain)
 # pca_plot<-ggplot(pca_data ,aes(x=PC1,y=PC4))+
 #   geom_point(aes(color=res,text=domain,shape=as.factor(label)),alpha=0.5)+
 #   theme_bw()
  

plotly::plot_ly(pca_data , type="scatter3d", 
                x = ~PC1, y = ~PC2, z = ~PC3, color = ~res, symbol = ~label,
                colors = c('blue', 'orange',"red","green"), 
                opacity=0.5, marker = list(size = 3),text = ~domain) 
LS0tCnRpdGxlOiAiQ1RVMTkiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShza2ltcikKYGBgCgpgYGB7cn0KY3R1MTk8LXJlYWRfY3N2KCIuLi9kYXRhc2V0cy9jdHUxOV9yZXN1bHQuY3N2IikKY3R1MTkgJT4lIGdyb3VwX2J5KExhYmVsTmFtZSkgJT4lIHN1bW1hcmlzZShuPW4oKSkKYGBgCiMgQ3JlYXRlIGRhdGFzZXQKYGBge3J9CmN0dTE5PC0gY3R1MTkgJT4lIHNlbGVjdChTdGF0ZSxMYWJlbE5hbWUpIApuYW1lcyhjdHUxOSk8LWMoIlN0YXRlIiwiY2xhc3MiKQpjdHUxOSRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDQsbmNoYXIoY3R1MTkkU3RhdGUpKQpjdHUxOTwtY3R1MTkgJT4lIGZpbHRlcihTdGF0ZSE9IiIpCgpjdHUxOSAlPiUgbnJvdygpCmN0dTE5ICU+JSBncm91cF9ieShjbGFzcykgJT4lIHN1bW1hcml6ZShuPW4oKSkKY3R1MTkgJT4lIHdyaXRlX2NzdigiLi4vZGF0YXNldHMvY3R1MTlzdWJzMi5jc3YiKQpuYW1lcyhjdHUxOSkKYGBgCgpgYGB7cn0KY3R1MTk8LXJlYWRyOjpyZWFkX2NzdigiZGF0YXNldHMvY3R1MTlzdWJzLmNzdiIpCgpjdHUxOTwtY3R1MTkgJT4lIG11dGF0ZShtb2RlbHNpemU9c3RyX2NvdW50KFN0YXRlLCIuIikpIApjdHUxOV9jbGVhbmVkPC1jdHUxOSAlPiUgZmlsdGVyICghaXMubmEoUG9ydCkpCgpjdHUxOV9jbGVhbmVkICU+JSBmaWx0ZXIoUG9ydCA8IDEwMjQpICU+JSBncm91cF9ieShtb2RlbHNpemUsUG9ydCkgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIHVuZ3JvdXAoKSAlPiUgbXV0YXRlKHRvdGFsPXN1bShuKSkgCgpjdHUxOV9jbGVhbmVkICU+JSBmaWx0ZXIobW9kZWxzaXplPDQpICU+JSBzZWxlY3QoU3RhdGUpCgpjdHUxOV9jbGVhbmVkJFN0YXRlIDwtIGN0dTE5X2NsZWFuZWQkU3RhdGUgJT4lIHN1YnN0cig0LDUwMDAwMDApCmdncGxvdChjdHUxOV9jbGVhbmVkICU+JSBmaWx0ZXIoUG9ydCA8IDEwMjQpKSsKICBnZW9tX2JveHBsb3QoYWVzKHg9YXMuZmFjdG9yKFgxKSx5PW1vZGVsc2l6ZSkpKwogIHRoZW1lX2J3KCkKICAKbmFtZXMoY3R1MTkpCmBgYApgYGB7cn0KY3R1MTk8LXJlYWRyOjpyZWFkX2NzdigiZGF0YXNldHMvY3R1MTlzdWJzLmNzdiIpCmN0dTE5PC1jdHUxOSAlPiUgbXV0YXRlKG1vZGVsc2l6ZT1zdHJfY291bnQoU3RhdGUsIi4iKSkgCmN0dTE5ICU+JSBmaWx0ZXIobW9kZWxzaXplID4xMDApICU+JSBncm91cF9ieShjbGFzcykgJT4lIHN1bW1hcmlzZShuPW4oKSkKCmN0dTE5ICU+JSBucm93KCkKc3VtbWFyeShjdHUxOSkKc2tpbShjdHUxOSAlPiUgbXV0YXRlKGNsYXNzPWFzLmZhY3RvcihjbGFzcykpKQoKY3R1MTkgJT4lIHNlbGVjdChTdGF0ZSkgJT4lIHVuaXF1ZSgpICU+JSBucm93CmBgYAoKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9MTB9CmNyZWF0ZV9oaXN0b2dyYW08LWZ1bmN0aW9uKHgpewogIHZhbGlkX2NoYXJhY3RlcnMgPC0gIiRhYmNkZWZnaGlBQkNERUZHSElyc3R1dnd4eXpSU1RVVldYWVowMTIzNDU2Nzg5IiAlPiUgc3RyX3NwbGl0KCIiKQogIHZhbGlkX2NoYXJhY3RlcnMgPC0gdmFsaWRfY2hhcmFjdGVyc1tbMV1dIAogIHZhbGlkX2NoYXJhY3RlcnNbNDhdPSJcXC4iCiAgdmFsaWRfY2hhcmFjdGVyc1s0OV09IlxcLCIKICB2YWxpZF9jaGFyYWN0ZXJzWzUwXT0iXFwrIgogIHZhbGlkX2NoYXJhY3RlcnNbNTFdPSJcXCoiCgogIGZyZXE8LSAoeCAlPiUgbWFwKGZ1bmN0aW9uKHgpIHN0cl9jb3VudCh4LHZhbGlkX2NoYXJhY3RlcnMpKSAlPiUgdW5saXN0KCkgJT4lIG1hdHJpeCggbmNvbCA9IDUxLCBieXJvdyA9IFRSVUUpICU+JSBjb2xTdW1zKCkpCiAgZnJlcTwtZnJlcS8gc3VtKCBzdHJfY291bnQoeCwiLiIpICkKICBwbG90PC1kYXRhLmZyYW1lKGZyZXE9ZnJlcSxzeW1ib2xzPXZhbGlkX2NoYXJhY3RlcnMpICU+JQogIGdncGxvdCgpKwogIGdlb21fY29sKGFlcyh4PXN5bWJvbHMseT1mcmVxKSxmaWxsPSdibGFjaycsY29sPSdibGFjaycpKwogIHRoZW1lX2J3KCkKICBwbG90Cn0KbiA8LSAoY3R1MTkgJT4lIGZpbHRlcihjbGFzcyA9PSAiTm9ybWFsIiAmIG1vZGVsc2l6ZSA8MTAwKSkkU3RhdGUgCgpuaDwtY3JlYXRlX2hpc3RvZ3JhbShuKQpuaCA8LSBuaCArICBsYWJzKHRpdGxlPSJDVFUxOSBzZXEgY2hhciBkaXN0cmlidXRpb24gZm9yIE5vcm1hbCBbbW9kZWxzaXplIDwxMDBdIikKCm0gPC0gKGN0dTE5ICU+JSBmaWx0ZXIoY2xhc3MgIT0gIk5vcm1hbCIgJiBtb2RlbHNpemUgPDEwMCkpJFN0YXRlIAoKbWg8LWNyZWF0ZV9oaXN0b2dyYW0obSkKbWggPC0gbWggKyAgbGFicyh0aXRsZT0iQ1RVMTkgc2VxIGNoYXIgZGlzdHJpYnV0aW9uIGZvciBNYWx3YXJlIFttb2RlbHNpemUgPDEwMF0iKQoKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UobmgsbWgpCgpgYGAKYGBge3J9CiNzb3VyY2UoInByZXByb2Nlc3MuUiIpCiNkYXRhc2V0czwtYnVpbGRfdHJhaW5fdGVzdChkYXRhc2V0ZmlsZSA9ICJkYXRhc2V0cy9jdHUxM3N1YnMuY3N2IixtYXhsZW4gPSBjdHVfbWF4bGVuKQojIFdBUk5JTkc6IHRvIGF2b2lkIHJlZ2VuZXJhdGluZyBkZSB0cmFpbiBhbmQgdGVzdCBzZXRzLCBqdXN0IHVuY29tbWVudHMgdGhlIGZvbGxvd2luZyBsaW5lcwojIFdBUk5JTkc6IHRoZXJlIGlzIG5vIGd1YXJhbnRlZSB0aGUgZmlsZXMgc2F2ZWQgY29ycmVzcG9uZCB0byBhcmdlbmNvbi5jc3YuIElmIHVuc3VyZSwganVzdCByZS1ydW4gYnVpbGRfdHJhaW5fdGVzdCgpCmxvYWQoZmlsZT0nZGF0YXNldHMvLnRyYWluX2RhdGFzZXRfa2VyYXMucmQnKQpsb2FkKGZpbGU9J2RhdGFzZXRzLy50ZXN0X2RhdGFzZXRfa2VyYXMucmQnKQpkYXRhc2V0czwtbGlzdCgpCmRhdGFzZXRzJHRyYWluPC10cmFpbl9kYXRhc2V0X2tlcmFzCmRhdGFzZXRzJHRlc3Q8LXRlc3RfZGF0YXNldF9rZXJhcwoKIyMjIEZ1bmN0aW9uIERlZmluaXRpb25zICMjIyMKZ2V0X3ByZWRpY3Rpb25zIDwtIGZ1bmN0aW9uKG1vZGVsLCB0ZXN0X2RhdGFzZXRfeCx0aHJlc2hvbGQ9MC41KSB7CiAgcHJlZHNwcm9iczwtbW9kZWwgJT4lIHByZWRpY3QodGVzdF9kYXRhc2V0X3gsIGJhdGNoX3NpemU9MjU2KQogIHByZWRzPC1pZmVsc2UocHJlZHNwcm9icz50aHJlc2hvbGQsMSwwKQogIHJldHVybiAocHJlZHMpCn0KYGBgCgpgYGB7cn0KbW9kZWw8LWtlcmFzOjpsb2FkX21vZGVsX2hkZjUoIm1vZGVscy9jdHUxOS1sc3RtX2VuZGdhbWUtNDAwLTEwX21vZGVsLmg1IikKc3VtbWFyeShtb2RlbCkKcHJlZHM8LWdldF9wcmVkaWN0aW9ucyhtb2RlbCA9IG1vZGVsLHRlc3RfZGF0YXNldF94ID0gIGRhdGFzZXRzJHRlc3QkZW5jb2RlLHRocmVzaG9sZCA9IDAuNSApCmBgYAoKYGBge3J9CnRlc3RfcmVzdWx0czwtZGF0YS5mcmFtZShwcmVkaWN0ZWRfY2xhc3M9cHJlZHMsY2xhc3M9aWZlbHNlKGdyZXBsKCJOb3JtYWwiLGRhdGFzZXRzJHRlc3QkbGFiZWwpICwwLDEpICxkb21haW49ZGF0YXNldHMkdGVzdCRkb21haW4sbGFiZWw9ZGF0YXNldHMkdGVzdCRsYWJlbCkgCiN0ZXN0X3Jlc3VsdHMKY2FyZXQ6OmNvbmZ1c2lvbk1hdHJpeChhcy5mYWN0b3IodGVzdF9yZXN1bHRzJHByZWRpY3RlZF9jbGFzcyksYXMuZmFjdG9yKHRlc3RfcmVzdWx0cyRjbGFzcyksIHBvc2l0aXZlPScxJywgbW9kZT0iZXZlcnl0aGluZyIgKQpgYGAKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CmZwPC0odGVzdF9yZXN1bHRzICU+JSBtdXRhdGUobW9kZWxzaXplPXN0cl9jb3VudChkb21haW4sIi4iKSkgICU+JSAgZmlsdGVyKGNsYXNzID09IDAgJiBwcmVkaWN0ZWRfY2xhc3MgPT0gMSkpCmZuPC0odGVzdF9yZXN1bHRzICU+JSBtdXRhdGUobW9kZWxzaXplPXN0cl9jb3VudChkb21haW4sIi4iKSkgICU+JSAgZmlsdGVyKGNsYXNzID09IDEgJiBwcmVkaWN0ZWRfY2xhc3MgPT0gMCkpCnRwPC0odGVzdF9yZXN1bHRzICU+JSBtdXRhdGUobW9kZWxzaXplPXN0cl9jb3VudChkb21haW4sIi4iKSkgICU+JSAgZmlsdGVyKGNsYXNzID09IDEgJiBwcmVkaWN0ZWRfY2xhc3MgPT0gMSkpCnRuPC0odGVzdF9yZXN1bHRzICU+JSBtdXRhdGUobW9kZWxzaXplPXN0cl9jb3VudChkb21haW4sIi4iKSkgICU+JSAgZmlsdGVyKGNsYXNzID09IDAgJiBwcmVkaWN0ZWRfY2xhc3MgPT0gMCkpCgoKZnBfZG9tYWluPC1mcCRkb21haW4KdHBfZG9tYWluPC10cCRkb21haW4KZm5fZG9tYWluPC1mbiRkb21haW4KdG5fZG9tYWluPC10biRkb21haW4KCgpmcF9oPC1jcmVhdGVfaGlzdG9ncmFtKGZwX2RvbWFpbikKZnBfaCA8LSBmcF9oICsgIGxhYnModGl0bGU9IkNUVTE5IHNlcSBjaGFyIGRpc3RyaWJ1dGlvbiBmb3IgRmFsc2UgUG9zaXRpdmUiKQojZnBfaCA8LSBmcF9oICsgeWxpbSgwLDUwMCkKCnRwX2g8LWNyZWF0ZV9oaXN0b2dyYW0odHBfZG9tYWluKQp0cF9oIDwtIHRwX2ggKyAgbGFicyh0aXRsZT0iQ1RVMTkgc2VxIGNoYXIgZGlzdHJpYnV0aW9uIGZvciBUcnVlIFBvc2l0aXZlIikKI3RwX2ggPC0gdHBfaCArIHlsaW0oMCw1MDApCgpmbl9oPC1jcmVhdGVfaGlzdG9ncmFtKGZuX2RvbWFpbikKZm5faCA8LSBmbl9oICsgIGxhYnModGl0bGU9IkNUVTE5IHNlcSBjaGFyIGRpc3RyaWJ1dGlvbiBmb3IgRmFsc2UgTmVnYXRpdmUiKQp0bl9oPC1jcmVhdGVfaGlzdG9ncmFtKHRuX2RvbWFpbikKdG5faCA8LSB0bl9oICsgIGxhYnModGl0bGU9IkNUVTE5IHNlcSBjaGFyIGRpc3RyaWJ1dGlvbiBmb3IgVHJ1ZSBOZWdhdGl2ZSIpCgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShmcF9oLHRwX2gsZm5faCx0bl9oLG5jb2w9MSkKI2xpYnJhcnkoc2NhbGVzKQojdHBfaCArIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YygwLDEwMDApLG9vYiA9IHJlc2NhbGVfbm9uZSkKI2ZwX2ggKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMoMCwxMDAwKSxvb2IgPSByZXNjYWxlX25vbmUpCmBgYAoKYGBge3J9CmZwJHR5cGU8LSJmcCIKdHAkdHlwZTwtInRwIgp0biR0eXBlPC0idG4iCmZuJHR5cGU8LSJmbiIKCnBsb3Q8LXJiaW5kKGZwLHRwLHRuLGZuKSAlPiUKICBnZ3Bsb3QoKSsKICBnZW9tX2JveHBsb3QoYWVzKHg9dHlwZSx5PW1vZGVsc2l6ZSksZmlsbD0nb3JhbmdlJykgKwogIHlsaW0oMCw1MDApKwogIHRoZW1lX2J3KCkKcGxvdApnZ3Bsb3RseShwbG90KQpgYGAKCiMjICBwY2EgMkQgcHJveWVjdGlvbgpgYGB7cn0Kc291cmNlKCJwcmVwcm9jZXNzLlIiKQpsaWJyYXJ5KGFiaW5kKQogIHRwIDwtIHRwICU+JSBzYW1wbGVfbigxMDAwKQogIGZwX3Rva2VuaXplZD10b2tlbml6ZShhcy5tYXRyaXgoZnAkZG9tYWluKSxmcCRsYWJlbCxtYXhsZW4gPSAxMDApCiAgdHBfdG9rZW5pemVkPXRva2VuaXplKGFzLm1hdHJpeCh0cCRkb21haW4pLHRwJGxhYmVsLG1heGxlbiA9IDEwMCkKICBmbl90b2tlbml6ZWQ9dG9rZW5pemUoYXMubWF0cml4KGZuJGRvbWFpbiksZm4kbGFiZWwsbWF4bGVuID0gMTAwKQogIHRuX3Rva2VuaXplZD10b2tlbml6ZShhcy5tYXRyaXgodG4kZG9tYWluKSx0biRsYWJlbCxtYXhsZW4gPSAxMDApCiAgCiAgCiAgCiAgZnBfdG9rZW5pemVkJHJlczwtcmVwKCJGUCIsIGxlbmd0aChmcF90b2tlbml6ZWQkZG9tYWluKSkKICB0cF90b2tlbml6ZWQkcmVzPC1yZXAoIlRQIiwgbGVuZ3RoKHRwX3Rva2VuaXplZCRkb21haW4pKQogIAogIGZuX3Rva2VuaXplZCRyZXM8LXJlcCgiRk4iLCBsZW5ndGgoZm5fdG9rZW5pemVkJGRvbWFpbikpCiAgdG5fdG9rZW5pemVkJHJlczwtcmVwKCJUTiIsIGxlbmd0aCh0bl90b2tlbml6ZWQkZG9tYWluKSkKICAKICAKICBtYWx3YXJlX3Jlc3VsdHM9bGlzdCgpCiAgbWFsd2FyZV9yZXN1bHRzJGVuY29kZTwtYWJpbmQoZnBfdG9rZW5pemVkJGVuY29kZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cF90b2tlbml6ZWQkZW5jb2RlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZuX3Rva2VuaXplZCRlbmNvZGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG5fdG9rZW5pemVkJGVuY29kZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxvbmc9MSkKICBtYWx3YXJlX3Jlc3VsdHMkZG9tYWluPC1jKGZwX3Rva2VuaXplZCRkb21haW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cF90b2tlbml6ZWQkZG9tYWluLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm5fdG9rZW5pemVkJGRvbWFpbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRuX3Rva2VuaXplZCRkb21haW4pCiAgICAgICAgICAgICAgICAgICAgICAKICBtYWx3YXJlX3Jlc3VsdHMkcmVzPC1jKGZwX3Rva2VuaXplZCRyZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICB0cF90b2tlbml6ZWQkcmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgZm5fdG9rZW5pemVkJHJlcywKICAgICAgICAgICAgICAgICAgICAgICAgIHRuX3Rva2VuaXplZCRyZXMKICAgICAgICAgICAgICAgICAgICAgICAgICkKICBtYWx3YXJlX3Jlc3VsdHMkbGFiZWw8LWMoYXMuY2hhcmFjdGVyKGZwX3Rva2VuaXplZCRsYWJlbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmNoYXJhY3Rlcih0cF90b2tlbml6ZWQkbGFiZWwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIoZm5fdG9rZW5pemVkJGxhYmVsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMuY2hhcmFjdGVyKHRuX3Rva2VuaXplZCRsYWJlbCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAKICAjbnJvdyhtYWx3YXJlX3Jlc3VsdHMkZW5jb2RlKQogICNsZW5ndGgobWFsd2FyZV9yZXN1bHRzJGxhYmVsKQogICNsZW5ndGgobWFsd2FyZV9yZXN1bHRzJGRvbWFpbikKICAKICBwY2E9cHJjb21wKG1hbHdhcmVfcmVzdWx0cyRlbmNvZGVbLDE6MjBdLGNlbnRlcj1UUlVFLHNjYWxlLj1UUlVFKQogIHBjYV9kYXRhPC1kYXRhLmZyYW1lKHBjYSR4LHJlcz1tYWx3YXJlX3Jlc3VsdHMkcmVzLGxhYmVsPW1hbHdhcmVfcmVzdWx0cyRsYWJlbCxkb21haW49bWFsd2FyZV9yZXN1bHRzJGRvbWFpbikKICMgcGNhX3Bsb3Q8LWdncGxvdChwY2FfZGF0YSAsYWVzKHg9UEMxLHk9UEM0KSkrCiAjICAgZ2VvbV9wb2ludChhZXMoY29sb3I9cmVzLHRleHQ9ZG9tYWluLHNoYXBlPWFzLmZhY3RvcihsYWJlbCkpLGFscGhhPTAuNSkrCiAjICAgdGhlbWVfYncoKQogIAoKcGxvdGx5OjpwbG90X2x5KHBjYV9kYXRhICwgdHlwZT0ic2NhdHRlcjNkIiwgCiAgICAgICAgICAgICAgICB4ID0gflBDMSwgeSA9IH5QQzIsIHogPSB+UEMzLCBjb2xvciA9IH5yZXMsIHN5bWJvbCA9IH5sYWJlbCwKICAgICAgICAgICAgICAgIGNvbG9ycyA9IGMoJ2JsdWUnLCAnb3JhbmdlJywicmVkIiwiZ3JlZW4iKSwgCiAgICAgICAgICAgICAgICBvcGFjaXR5PTAuNSwgbWFya2VyID0gbGlzdChzaXplID0gMyksdGV4dCA9IH5kb21haW4pIApgYGAKCg==